package com.example.springapplicationdemo.handlerexceptionresolver;

import com.alibaba.fastjson.JSON;
import com.example.springapplicationdemo.exception.BusinessException;
import com.example.springapplicationdemo.vo.RestResVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class RestHandlerExceptionResolver implements HandlerExceptionResolver {
    private static final Logger LOGGER = LoggerFactory.getLogger(RestHandlerExceptionResolver.class);

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        if(isRestRequest(handler) && isAcceptException(ex)){
            RestResVo<Void> restResVo = RestResVo.error((BusinessException)ex);
            try {
                response.getWriter().println(JSON.toJSONString(restResVo));
            }catch (Exception e){
                LOGGER.error("failed to write json {}", restResVo, e);
            }
            // empty ModelAndView说明已经处理
            return new ModelAndView();
        }
        return null;
    }

    private boolean isRestRequest(Object handler) {
        if (handler instanceof HandlerMethod){
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            return AnnotationUtils.findAnnotation(handlerMethod.getMethod(), ResponseBody.class) !=null ||
                    AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), ResponseBody.class) != null;
        }
        return false;
    }

    private boolean isAcceptException(Exception ex) {
        return ex instanceof BusinessException;
    }
}
